package org.picasaapp.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.ScriptElement;

/**
 * Provides access to the Picasa Web Albums.
 */
public final class PicasaWeb {
    /**
     * A JavaScript overlay object for a single album.
     */
    public static class Album extends JavaScriptObject {
        protected Album() {
        }

        /**
         * Returns the title of this album.
         */
        public final native String getTitle() /*-{
            return this.title.$t;
        }-*/;

        /**
         * Returns the ID of this album.
         */
        public final native String getID() /*-{
            return this.gphoto$id.$t;
        }-*/;
        
        /**
         * Returns the name of this album.
         */
        public final native String getName() /*-{
            return this.gphoto$name.$t;
        }-*/;

        /**
         * Returns the thumbnail URL of this album.
         */
        public final native String getThumbnailURL() /*-{
            return this.media$group.media$thumbnail[0].url;
        }-*/;

        /**
         * Returns the link to fetch the photos of this album as JSON.
         */
        public final native String getURL() /*-{
            for (var i = 0; i < this.link.length; ++i) {
                if (this.link[i].rel ==
                    "http://schemas.google.com/g/2005#feed") {
                    return this.link[i].href;
                }
            }
        }-*/;
    }

    /**
     * A JavaScript overlay object for the Picasa albums JSON response.
     */
    public static class Albums extends JavaScriptObject {

        protected Albums() {
        }

        /**
         * Returns the number of albums.
         */
        public final native int getNumAlbums() /*-{
            return this.feed.entry.length;
        }-*/;

        /**
         * Returns the {@link Album} at the given position.
         */
        public final native Album getAlbum(int index) /*-{
            return this.feed.entry[index];
        }-*/;

        /**
         * Returns the author name.
         */
        public final native String getAuthorName() /*-{
            return this.feed.author[0].name.$t;
        }-*/;
    }
    
    /**
     * A JavaScript overlay object for a single photo.
     */
    public static class Photo extends JavaScriptObject {
        private native String doGetWidth() /*-{
            return this.gphoto$width.$t;
        }-*/;

        private native String doGetHeight() /*-{
            return this.gphoto$height.$t;
        }-*/;

        protected Photo() {
        }

        /**
         * Returns the title of this photo.
         */
        public final native String getTitle() /*-{
            return this.title.$t;
        }-*/;

        public final native String getID() /*-{
            return this.gphoto$id.$t;
        }-*/;
        
        public final native String getURL() /*-{
            return this.content.src;
        }-*/;

        /**
         * Returns the URL of the photo with the given image width.
         */
        public final String getURL(int width) {
            String url = getURL();
            int lastSlashPos = url.lastIndexOf('/');
            return url.substring(0, lastSlashPos + 1) +
                's' + width + url.substring(lastSlashPos);
        }

        public final int getWidth() {
            return Integer.parseInt(doGetWidth());
        };

        public final int getHeight() {
            return Integer.parseInt(doGetHeight());
        };

        /**
         * Returns the thumbnail URL of this photo.
         */
        public final native String getThumbnailURL() /*-{
            return this.media$group.media$thumbnail[1].url;
        }-*/;
        
        public final double getScaleFactor(int maxWidth, int maxHeight) {
            return Math.min(
                    maxWidth / (double) getWidth(),
                    maxHeight / (double) getHeight());
        }
    }

    /**
     * A JavaScript overlay object for the Picasa photos JSON response.
     */
    public static class Photos extends JavaScriptObject {
        protected Photos() {
        }

        /**
         * Returns the number of photos.
         */
        public final native int getNumPhotos() /*-{
            return this.feed.entry.length;
        }-*/;

        /**
         * Returns the {@link Photo} at the given position.
         */
        public final native Photo getPhoto(int index) /*-{
            return this.feed.entry[index];
        }-*/;
    }

    private static int callbackCounter = 0;

    private static native void registerCallback(String name,
            Callback<?> callback) /*-{
        $wnd[name] = function(response) {
            callback.@org.picasaapp.client.PicasaWeb.Callback::callback(Ljava/lang/Object;)(response);
        }
    }-*/;

    /**
     * A simple callback interface.
     * 
     * @param <T>
     *          the type of the response
     */
    public static interface Callback<T> {
        void callback(T response);
    }
    
    public static void request(String url, Callback<?> callback) {
        // Every requests gets a new callback, so that we can make many
        // requests in parallel.
        String callbackName = "cb" + callbackCounter++;
        url += "&callback=" + callbackName;
        registerCallback(callbackName, callback);
        ScriptElement element = Document.get().createScriptElement();
        element.setSrc(url);
        Document.get().getBody().appendChild(element);
    }
}
